package gupao.concurrency.threads;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.util.AbstractSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

public class TaskStatusDemo {

    static
    @Getter
    @RequiredArgsConstructor
    @EqualsAndHashCode
    class RouteInfo{
        private final String ip;
        private final Integer port;
        private final String group;
    }

    static
    class RouteTable{
        private final ConcurrentHashMap<String, CopyOnWriteArraySet<RouteInfo>>
                routeTable = new ConcurrentHashMap<>(512);

        public void add(RouteInfo route){
            Set<RouteInfo> routes = routeTable.computeIfAbsent(route.getGroup(),
                    g -> new CopyOnWriteArraySet<>());
            routes.add(route);
        }
        public Set<RouteInfo> getRoutes(String group){
            return routeTable.get(group);
        }
        public void remove(RouteInfo route){
            Set<RouteInfo> routes = getRoutes(route.getGroup());
            if(routes != null){
                routes.remove(route);
            }
        }
    }


    static
    class ThreadLocalContext{
        private final static ThreadLocal<String> USER_ID_THREAD_LOCAL = new ThreadLocal<>();
        private final static ThreadLocal<TaskJob> TASK_JOB_THREAD_LOCAL = new ThreadLocal<>();
        static void setUserId(String userId){
            USER_ID_THREAD_LOCAL.set(userId);
        }
        static void setTaskJob(TaskJob job){
            TASK_JOB_THREAD_LOCAL.set(job);
        }
        static String getUserId(){
            return USER_ID_THREAD_LOCAL.get();
        }
        public TaskJob getTaskJob(){
            return TASK_JOB_THREAD_LOCAL.get();
        }
    }

    static
    abstract class AbstractJobTask implements Runnable{
        void beforeRun(){
            ThreadLocalContext.setTaskJob(queryTaskJob());
            ThreadLocalContext.setUserId(queryUserId());
        }
        void afterRun(){

        }
        abstract void innerRun();
        @Override
        public void run() {
            beforeRun();
            try{
                innerRun();
            }finally {
                afterRun();
            }
        }
    }

    static String queryUserId(){
        return null;
    }

    static TaskJob queryTaskJob(){
        return null;
    }

    @Getter
    @RequiredArgsConstructor
    static abstract class AbstractTask implements Runnable {
        final JobContext context;
        @Override
        public void run() {
            beforeRun();
            try{
                innerRun();
            } finally {
                afterRun();
            }
        }
        abstract void innerRun();
        public void beforeRun(){
        }
        public void afterRun(){
        }
    }

    @Getter
    @RequiredArgsConstructor
    static class JobContext{
        private final String userId;
        private final TaskJob job;
    }

    @Getter
    @RequiredArgsConstructor
    static class TaskJob{
        private final Long amaJobId;
        private final String jobName;
        private final Long startYear;
        private final Long startQtr;
        private final Long endYear;
        private final Long endQtr;
        private final Long numOfQtrs;
        private final String isFrozen;
        private final Long levelNo;
        private final String jobType;
    }

    static
    class TempResult{
        private Object qaf;
        private Object qafCapital;
        private Object factor;
        private Object factorAdj;
        private Object factorCap;

        public synchronized void setQafResult(Object qaf) {
            this.qaf = qaf;
            this.qafCapital = calQafCapital(qaf);
        }

        public void setFactorResult(Object factor){
            synchronized (factor){
                this.factor = factor;
                this.factorAdj = (calcFactorAdj(factor));
                this.factorCap = (calcFactorCap(factor));
            }
        }



       Object calQafCapital(Object qafResult){
            return null;
       }
       Object calcFactorAdj(Object factor){
            return null;
       }
       Object calcFactorCap(Object factor){
            return null;
       }
    }

}
